// 导入koa, 和koa1.x不同，在koa2中，导入的是一个class，因此大写表示
const Koa = require('koa');
// 监听的端口号
const port = process.env.PORT || 3000;
// 定义了一个常量用来判断当前环境是否是production环境
const isProduction = process.env.NODE_ENV === 'production';

/**
 * 注意require('koa-router')返回的是函数: const router = require('koa-router')();// 省略写法: 导入并调用(廖雪峰博客老写法)
 * ????-升级了: 用法改变为实例化
 * 目的: 为了根据不同的url渲染不同页面或者返回不同数据；不用每次都在app.use()中去判断,而是从上到下自动匹配; 
 */
const Router = require('koa-router')


/** ⅰ:
 * =>post请求通常会发送一个表单，或者JSON，它作为request的body发送，但无论是Node.js提供的原始request对象，
 * 还是koa提供的request对象，都不提供解析request的body的功能
 * 
 * =>引入另一个middleware来解析原始request请求，然后，把解析后的参数，绑定到ctx.request.body中
 * 原理: 在一个Promise中监听ctx.req.on('data', cb-累加); ctx.req.on('end',()=>resolve(累加的全部字符串))
 */
const bodyParser = require('koa-bodyparser');
// ⅱ: 静态目录中间件
// let staticFiles = require('./middleware/static-files.js');
const static = require('koa-static');
// ⅲ: ejs模板中间件
// const templating = require('./middleware/templating.js');
// ⅳ: 导入视图controller middleware:
// const controller = require('./controller.js');
// ⅴ: 验证token是否正确插件
const passport = require('koa-passport');
// Ⅵ: 引入自定义服务端接口路由
const users = require('./routes/users');
// Ⅶ: 


/** -------------------------------引入-end------------------------------------ */
// 创建一个Koa实例对象, 表示web app本身  ⅧⅨⅩⅪⅫ  ⅶⅷⅸⅹ
const app = new Koa();
const router = new Router();
/** -------------------------------使用-start----------------------------------*/

// ##############视图

// B站
// require('koa-ejs')(app, {
//     root: path.join(__dirname, 'view'),
//     layout: 'template',
//     viewExt: 'html',
//     cache: false,//开发模式下,无缓存,有debug; 而生产环境有缓存,无debug
//     debug: true
// });

// koa-generator脚手架工具
//  必须在使用任何路由器之前使用
// root：您的意见所在的位置。必须是绝对路径。所有渲染的视图均相对于此路径
app.use(require('koa-views')('views', {
    root: __dirname + '/views',
    default: 'ejs',
    // 不能用于ctx.body接收渲染的模板字符串
    autoRender: false
}));
app.use(async function (ctx) {
    await ctx.render('user');
});
// ##############视图end



/** Ⅰ:
 * koa-bodyparser必须在router之前被注册到app对象上: 才能起到解析的作用
 */
app.use(bodyParser())

/**
 * koa middleware: 第一个middleware是记录URL以及页面执行时间
 * 对于任何请求， app将调用该异步函数处理请求
 * 
 * 参数ctx 是由koa传入的封装了request和response的变量，我们可以通过它访问request和response
 * next是koa传入的将要处理的下一个异步函数
 * 
 * 上面的异步函数中，我们首先用await next();处理下一个异步函数，然后，设置response的Content-Type和内容。
 * 由async标记的函数称为异步函数，在异步函数中，可以用await调用另一个异步函数，这两个关键字将在ES7中引入。
 */
app.use(async (ctx, next) => {
    var
        start = Date.now(),
        execTime;
    await next();
    execTime = Date.now() - start;
    console.log(`Process ${ctx.request.method} ${ctx.request.url}..., response-time is ${execTime}ms`);
    ctx.response.set('X-Response-Time', `${execTime}ms`);
});

/**
 * Ⅱ: 通过app实例使用静态目录中间件
 * 使用方法(省略static): <link rel="stylesheet" href="css/style.css"> OR http://localhost:3000/我是静态资源.txt
 */
// app.use(staticFiles('/static/', __dirname + '/static'));
app.use(static(__dirname + '/static'))

/** Ⅲ:
 * Node.js在全局变量process中定义了一个环境变量env.NODE_ENV(生产环境上必须配置环境变量NODE_ENV = 'production'，而开发环境不需要配置，实际上NODE_ENV可能是undefined，所以判断的时候，不要用NODE_ENV === 'development')
 * 如果是生产，就使用缓存; 如果不是，就关闭缓存。
 * 因为开发阶段关闭缓存后，我们修改View，可以直接刷新浏览器看到效果，否则，每次修改都必须重启Node程序，会极大地降低开发效率
 */

// app.use(templating('views', {
//     noCache: !isProduction,
//     watch: !isProduction
// }));

// Ⅳ: 使用视图middleware:
// app.use(controller());

// Ⅴ: 初始化
app.use(passport.initialize())
app.use(passport.session())
// 回调到另一个文件中(验证token - 成功则把信息挂载到ctx.state中)
require('./utils/passportCB.js')(passport)

// ⅵ: 使用路由,并配置别名(访问时地址需加上别名)
router.use('/api/users', users)


// 在配置完所有路由地址之后, 把前面所有定义的方法添加到app应用上去
app.use(router.routes()).use(router.allowedMethods());

// 监听3000端口-port
// 只不过是`http.createServer(app.callback()).listen(3000);`的语法糖
// 还可以将同一个应用程序同时作为HTTP和HTTPS或多个地址: 监听多个端口 或 http和https
app.listen(port, () => {
    console.log(`app started at port ${port}...`);
});

